package api

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
	"mxshop-api/user-web/global"
	"mxshop-api/user-web/global/response"
	"mxshop-api/user-web/proto"
	"mxshop-api/user-web/utils"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

// HandleGrpcErrorToHttp 将grpc错误转为http的错误
func HandleGrpcErrorToHttp(err error, c *gin.Context) {
	if err != nil {
		code := http.StatusInternalServerError
		msg := "服务内部错误"
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				code = http.StatusNotFound
				msg = e.Message()
			case codes.InvalidArgument:
				code = http.StatusBadRequest
				msg = "参数错误"
			case codes.Unavailable:
				msg = "用户服务不可达"
			}

		}
		c.JSON(code, gin.H{
			"msg": msg,
		})
	}
}

// GetUserList 获取用户列表接口
func GetUserList(c *gin.Context) {
	// 调用用户的grpc服务
	connAddress := fmt.Sprintf("%s:%d", global.ServerConfig.UserSrv.Host, global.ServerConfig.UserSrv.Port)
	conn, err := grpc.Dial(connAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		zap.S().Errorf("连接用户服务失败:%s", err.Error())
		c.JSON(http.StatusInternalServerError, gin.H{
			"msg": "服务内部错误",
		})
		return
	}
	defer conn.Close()

	pn := c.DefaultQuery("pn", "0")
	pnInt, _ := strconv.Atoi(pn)
	pSize := c.DefaultQuery("psize", "10")
	pSizeInt, _ := strconv.Atoi(pSize)

	// 调用接口
	client := proto.NewUserClient(conn)
	userResponse, err := client.GetUserList(context.Background(), &proto.PageInfo{
		Pn:    uint32(pnInt),
		PSize: uint32(pSizeInt),
	})
	if err != nil {
		zap.S().Errorf("查询用户列表失败:%s", err.Error())
		HandleGrpcErrorToHttp(err, c)
		return
	}
	var result []any
	for _, user := range userResponse.Data {
		data := response.UserResponse{
			Id:       user.Id,
			NickName: user.NickName,
			Gender:   user.Gender,
			Birthday: response.JsonTime(time.Unix(int64(user.Birthday), 0)),
			Mobile:   user.Mobile,
		}
		result = append(result, data)
	}
	c.JSON(http.StatusOK, result)
}

func RemoveTopStruct(fieds map[string]string) string {
	for _, v := range fieds {
		return v
	}
	return ""
}

// PasswordLogin 账号密码登陆
func PasswordLogin(c *gin.Context) {
	var params map[string]string
	if err := c.ShouldBindJSON(&params); err != nil {
		zap.S().Error(err)
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "参数错误",
		})
		return
	}
	mobile := params["mobile"]
	password := params["password"]
	if password == "" || mobile == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "缺少参数",
		})
		return
	}

	// 验证密码是否合法
	if len(password) < 3 || len(password) > 20 {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "密码不合法",
		})
		return
	}

	//验证手机号是否合法
	if ok, _ := regexp.MatchString(`^1([38][0-9]|14[579]|5[^4]|16[6]|7[1-35-8]|9[189])\d{8}$`, mobile); !ok {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "手机号码不合法",
		})
		return
	}

	// 调用用户的grpc服务
	connAddress := fmt.Sprintf("%s:%d", global.ServerConfig.UserSrv.Host, global.ServerConfig.UserSrv.Port)
	conn, err := grpc.Dial(connAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		zap.S().Errorf("连接用户服务失败:%s", err.Error())
		c.JSON(http.StatusInternalServerError, gin.H{
			"msg": "服务内部错误",
		})
		return
	}
	defer conn.Close()
	// 调用接口
	client := proto.NewUserClient(conn)

	// 登录逻辑
	if resp, err := client.GetUserByMobile(context.Background(), &proto.MobileRequest{
		Mobile: mobile,
	}); err != nil {
		zap.S().Error(err)
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				c.JSON(http.StatusBadRequest, gin.H{"msg": "用户不存在"})
			default:
				c.JSON(http.StatusInternalServerError, gin.H{"msg": "登录失败"})
			}
		}
		return
	} else {
		// 进行密码验证
		passResp, passErr := client.CheckPassword(context.Background(), &proto.CheckPasswordInfo{
			Password:        password,
			EncryptPassword: resp.Password,
		})
		if passErr != nil || !passResp.Success {
			if passErr != nil {
				zap.S().Error(passErr)
			}
			c.JSON(http.StatusInternalServerError, gin.H{"msg": "登录失败"})
			return
		}

		//生成token
		j := utils.NewJWT()
		token, err := j.CreateToken(resp.Id, resp.Role, resp.NickName)
		if err != nil {
			zap.S().Error(err)
			c.JSON(http.StatusInternalServerError, gin.H{"msg": "生成token失败"})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"id":        resp.Id,
			"nick_name": resp.NickName,
			"token":     token,
		})
	}

}
